/**
 * @file	
 * @author	chipsea
 * @brief	
 * @version	0.1
 * @date	2020-11-30
 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd.
 * @note
 */

/**************************************************************************************************
  Filename:       AudioGATTprofile.c
  Revised:         
  Revision:       

  Description:    This file contains the Simple GATT profile sample GATT service 
                  profile for use with the BLE sample application.

 
**************************************************************************************************/

/*********************************************************************
 * INCLUDES
 */
#include "bcomdef.h"
#include "OSAL.h"
#include "linkdb.h"
#include "att.h"
#include "gatt.h"
#include "gatt_uuid.h"
#include "gattservapp.h"
#include "gapbondmgr.h"

#include "AudioGATTprofile.h"

#include "log.h"
//#include "common.h"
#include "peripheral.h"

#include "hidkbd.h"




/*********************************************************************
 * MACROS
 */

/*********************************************************************
 * CONSTANTS
 */

#define SERVAPP_NUM_ATTR_SUPPORTED        8

/*********************************************************************
 * TYPEDEFS
 */
 
#define AUDIO_BASE_UUID_128( uuid )  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, \
                                  0x00, 0x40, 0x51, 0x04, LO_UINT16( uuid ), HI_UINT16( uuid ), 0x00, 0xF0

/*********************************************************************
 * GLOBAL VARIABLES
 */


uint8 char1Tx_length=0; 
uint8 char2Tx_length=0; 

// Audio GATT Profile Service UUID: 0xFF01

CONST uint8 AudioProfileServUUID[ATT_UUID_SIZE] =
{ 
  AUDIO_BASE_UUID_128(AUDIOPROFILE_SERV_UUID)
};

// Characteristic 1 UUID: 0xFFF1
CONST uint8 AudioProfilechar1UUID[ATT_UUID_SIZE] =
{ 
  AUDIO_BASE_UUID_128(AUDIOPROFILE_CHAR1_UUID)
};

// Characteristic 2 UUID: 0xFFF2
CONST uint8 AudioProfilechar2UUID[ATT_UUID_SIZE] =
{ 
  AUDIO_BASE_UUID_128(AUDIOPROFILE_CHAR2_UUID)
};



/*********************************************************************
 * EXTERNAL VARIABLES
 */

/*********************************************************************
 * EXTERNAL FUNCTIONS
 */

/*********************************************************************
 * LOCAL VARIABLES
 */

static AudioProfileCBs_t *AudioProfile_AppCBs = NULL;

/*********************************************************************
 * Profile Attributes - variables
 */

// Simple Profile Service attribute
static CONST gattAttrType_t AudioProfileService = { ATT_UUID_SIZE, AudioProfileServUUID };


// Audio Profile Characteristic 1 Properties
static uint8 AudioProfileChar1Props =  GATT_PROP_NOTIFY|GATT_PROP_READ;

// Characteristic 1 Value
 uint8 AudioProfileChar1[AUDIOPROFILE_CHAR1_LEN];

 // Audio Profile Characteristic 1 Configuration Each client has its own
 // instantiation of the Client Characteristic Configuration. Reads of the
 // Client Characteristic Configuration only shows the configuration for
 // that client and writes only affect the configuration of that client.
 static gattCharCfg_t AudioProfileChar1Config[GATT_MAX_NUM_CONN];


// Audio Profile Characteristic 2 User Description
//static uint8 AudioProfileChar1UserDesp[] = "RX CHAR\0";



// Audio Profile Characteristic 1 Properties
static uint8 AudioProfileChar2Props = GATT_PROP_NOTIFY|GATT_PROP_READ;

// Characteristic 1 Value
 uint8 AudioProfileChar2[AUDIOPROFILE_CHAR2_LEN];

// Audio Profile Characteristic 1 User Description
//static uint8 AudioProfileChar2UserDesp[] = "TX CHAR\0";

// Audio Profile Characteristic 1 Configuration Each client has its own
// instantiation of the Client Characteristic Configuration. Reads of the
// Client Characteristic Configuration only shows the configuration for
// that client and writes only affect the configuration of that client.
static gattCharCfg_t AudioProfileChar2Config[GATT_MAX_NUM_CONN];


/*********************************************************************
 * Profile Attributes - Table
 */

static gattAttribute_t AudioProfileAttrTbl[] = 
{
    // =========== Simple Profile Service
    { 
        { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */
        GATT_PERMIT_READ,                         /* permissions */
        0,                                        /* handle */
        (uint8 *)&AudioProfileService            /* pValue */
    },

    // ----------------------------------------------------------------------
    // Characteristic 1 Declaration,
    { 
        { ATT_BT_UUID_SIZE, characterUUID },
        GATT_PERMIT_READ, 
        0,
        &AudioProfileChar1Props 
    },

    // Characteristic Value 1
    { 
        { ATT_UUID_SIZE, AudioProfilechar1UUID },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE, 
        0, 
        (uint8 *)&AudioProfileChar1 
    },

   // Characteristic 1 User Description, this field is optional
//   { 
//       { ATT_BT_UUID_SIZE, charUserDescUUID },
//       GATT_PERMIT_READ, 
//       0, 
//        AudioProfileChar1UserDesp 
//    },    

         // Characteristic 1 configuration
    { 
        { ATT_BT_UUID_SIZE, clientCharCfgUUID },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE, 
        0, 
        (uint8 *)AudioProfileChar1Config 
    }, 

    // ----------------------------------------------------------------------
    // Characteristic 2 Declaration,
    { 
        { ATT_BT_UUID_SIZE, characterUUID },
        GATT_PERMIT_READ, 
        0,
        &AudioProfileChar2Props 
    },

    // Characteristic Value 2
    { 
        { ATT_UUID_SIZE, AudioProfilechar2UUID },
        GATT_PERMIT_READ, 
        0, 
        AudioProfileChar2 
    },

    // Characteristic 2 configuration
    { 
        { ATT_BT_UUID_SIZE, clientCharCfgUUID },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE, 
        0, 
        (uint8 *)AudioProfileChar2Config 
    }, 

    // Characteristic 2 User Description
  //  { 
 //       { ATT_BT_UUID_SIZE, charUserDescUUID },
 //       GATT_PERMIT_READ, 
 //       0, 
 //       AudioProfileChar2UserDesp 
//    }, 
 

};


/*********************************************************************
 * LOCAL FUNCTIONS
 */
static uint8 AudioProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr, 
                            uint8 *pValue, uint16 *pLen, uint16 offset, uint8 maxLen );
static bStatus_t AudioProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
                                 uint8 *pValue, uint16 len, uint16 offset );

static void AudioProfile_HandleConnStatusCB( uint16 connHandle, uint8 changeType );


/*********************************************************************
 * PROFILE CALLBACKS
 */
// Audio Profile Service Callbacks
CONST gattServiceCBs_t AudioProfileCBs =
{
    AudioProfile_ReadAttrCB,  // Read callback function pointer
    AudioProfile_WriteAttrCB, // Write callback function pointer
    NULL                       // Authorization callback function pointer
};

/*********************************************************************
 * PUBLIC FUNCTIONS
 */

/*********************************************************************
 * @fn      AudioProfile_AddService
 *
 * @brief   Initializes the Simple Profile service by registering
 *          GATT attributes with the GATT server.
 *
 * @param   services - services to add. This is a bit map and can
 *                     contain more than one service.
 *
 * @return  Success or Failure
 */
bStatus_t AudioProfile_AddService( uint32 services )
{
    uint8 status = SUCCESS;
  
    // Initialize Client Characteristic Configuration attributes
    GATTServApp_InitCharCfg( INVALID_CONNHANDLE, AudioProfileChar1Config );
    GATTServApp_InitCharCfg( INVALID_CONNHANDLE, AudioProfileChar2Config );
  
    // Register with Link DB to receive link status change callback
    VOID linkDB_Register(AudioProfile_HandleConnStatusCB );  
    
    if ( services & AUDIOPROFILE_SERVICE )
    {
      // Register GATT attribute list and CBs with GATT Server App
      status = GATTServApp_RegisterService( AudioProfileAttrTbl, 
                                            GATT_NUM_ATTRS( AudioProfileAttrTbl ),
                                            &AudioProfileCBs );
    }
  
    return ( status );
}


/*********************************************************************
 * @fn      AudioProfile_RegisterAppCBs
 *
 * @brief   Registers the application callback function. Only call 
 *          this function once.
 *
 * @param   callbacks - pointer to application callbacks.
 *
 * @return  SUCCESS or bleAlreadyInRequestedMode
 */
bStatus_t AudioProfile_RegisterAppCBs( AudioProfileCBs_t *appCallbacks )
{
  if ( appCallbacks )
  {
    AudioProfile_AppCBs = appCallbacks;
    
    return ( SUCCESS );
  }
  else
  {
    return ( bleAlreadyInRequestedMode );
  }
}
  
/*********************************************************************
 * @fn      AudioProfile_SetParameter
 *
 * @brief   Set a Simple Profile parameter.
 *
 * @param   param - Profile parameter ID
 * @param   len - length of data to right
 * @param   value - pointer to data to write.  This is dependent on
 *          the parameter ID and WILL be cast to the appropriate 
 *          data type (example: data type of uint16 will be cast to 
 *          uint16 pointer).
 *
 * @return  bStatus_t
 */
bStatus_t AudioProfile_SetParameter( uint8 param, uint8 len, void *value )
{
    bStatus_t ret = SUCCESS;
    switch ( param )
    {
      case AUDIOPROFILE_CHAR1:
        if ( len >0) 
        {
          VOID osal_memcpy( AudioProfileChar1, value, len );
					char1Tx_length=len;
            
          ret=GATTServApp_ProcessCharCfg( AudioProfileChar1Config, AudioProfileChar1, FALSE,
                                    AudioProfileAttrTbl, GATT_NUM_ATTRS( AudioProfileAttrTbl ),
                                    INVALID_TASK_ID );   
          if(ret!=SUCCESS)
          {
          // LOG("Notify_error:%d\n\r",ret);
		  }
									
        }
        else
        {
          ret = bleInvalidRange;
        }
        break;
      case AUDIOPROFILE_CHAR2:
        if ( len >0) 
        {
          VOID osal_memcpy( AudioProfileChar2, value, len );
					char2Tx_length=len;
            
          ret=GATTServApp_ProcessCharCfg( AudioProfileChar2Config, AudioProfileChar2, FALSE,
                                    AudioProfileAttrTbl, GATT_NUM_ATTRS( AudioProfileAttrTbl ),
                                    INVALID_TASK_ID );   

		  if(ret!=SUCCESS)
          {
          // LOG("Notify_error:%d\nr",ret);
		  }
        }
        else
        {
          ret = bleInvalidRange;
        }
        break;
          
      default:
        ret = INVALIDPARAMETER;
        break;
    }
    
    return ( ret );
}

/*********************************************************************
 * @fn      AudioProfile_GetParameter
 *
 * @brief   Get a Audio Profile parameter.
 *
 * @param   param - Profile parameter ID
 * @param   value - pointer to data to put.  This is dependent on
 *          the parameter ID and WILL be cast to the appropriate 
 *          data type (example: data type of uint16 will be cast to 
 *          uint16 pointer).
 *
 * @return  bStatus_t
 */
bStatus_t AudioProfile_GetParameter( uint8 param, void *value )
{
    bStatus_t ret = SUCCESS;
    switch ( param )
    {
      
      default:
        ret = INVALIDPARAMETER;
        break;
    }
    
    return ( ret );
}

/*********************************************************************
 * @fn          AudioProfile_ReadAttrCB
 *
 * @brief       Read an attribute.
 *
 * @param       connHandle - connection message was received on
 * @param       pAttr - pointer to attribute
 * @param       pValue - pointer to data to be read
 * @param       pLen - length of data to be read
 * @param       offset - offset of the first octet to be read
 * @param       maxLen - maximum length of data to be read
 *
 * @return      Success or Failure
 */
static uint8 AudioProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr, 
                            uint8 *pValue, uint16 *pLen, uint16 offset, uint8 maxLen )
{
    bStatus_t status = SUCCESS;
  
    // If attribute permissions require authorization to read, return error
    if ( gattPermitAuthorRead( pAttr->permissions ) )
    {
      // Insufficient authorization
      return ( ATT_ERR_INSUFFICIENT_AUTHOR );
    }
    
    // Make sure it's not a blob operation (no attributes in the profile are long)
    if ( offset > 0 )
    {
      return ( ATT_ERR_ATTR_NOT_LONG );
    }
   
    if ( pAttr->type.len == ATT_BT_UUID_SIZE||pAttr->type.len == ATT_UUID_SIZE )
    {
      
      AudioProfile_Read(connHandle,pAttr,pValue,pLen,offset,maxLen);
    }
  
  
    return ( status );
}

/*********************************************************************
 * @fn      AudioProfile_WriteAttrCB
 *
 * @brief   Validate attribute data prior to a write operation
 *
 * @param   connHandle - connection message was received on
 * @param   pAttr - pointer to attribute
 * @param   pValue - pointer to data to be written
 * @param   len - length of data
 * @param   offset - offset of the first octet to be written
 *
 * @return  Success or Failure
 */
static bStatus_t AudioProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
                                 uint8 *pValue, uint16 len, uint16 offset )
{
    bStatus_t status = SUCCESS;
    uint8 notifyApp = 0xFF;
    
    // If attribute permissions require authorization to write, return error
    if ( gattPermitAuthorWrite( pAttr->permissions ) )
    {
      // Insufficient authorization
      return ( ATT_ERR_INSUFFICIENT_AUTHOR );
    }
    
  if ( pAttr->type.len == ATT_BT_UUID_SIZE )
  {
    // 16-bit UUID
    uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
    switch ( uuid )
    {
     


      case GATT_CLIENT_CHAR_CFG_UUID:
        status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
                                                 offset, GATT_CLIENT_CFG_NOTIFY );
       if ( status == SUCCESS )
		{
		 // uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] );
		  if(pAttr->handle==AudioProfileAttrTbl[3].handle)
		  {
           LOG("audio start cmd enable\n\r");
		  }
		  else if(pAttr->handle==AudioProfileAttrTbl[6].handle)
		  {
           LOG("audio data transf enable\n\r");
		   
		  // if(charCfg==0x0001)
		   //osal_start_timerEx(hidKbdTaskId, HID_KEY_TEST_EVT, 8000);	
		   
		  }
		}
												 

        break;
        
      default:
        // Should never get here! (characteristics 2 and 4 do not have write permissions)
        status = ATT_ERR_ATTR_NOT_FOUND;
        break;
    }
  }
    else
    {
      // 128-bit UUID
      status = ATT_ERR_INVALID_HANDLE;
    }
  
    // If a charactersitic value changed then callback function to notify application of change
  if ( (notifyApp != 0xFF ) && AudioProfile_AppCBs && AudioProfile_AppCBs->pfnAudioProfileChange )
  {
    AudioProfile_AppCBs->pfnAudioProfileChange( notifyApp );  
  }
    
    return ( status );
}

/*********************************************************************
 * @fn          AudioProfile_HandleConnStatusCB
 *
 * @brief       Audio Profile link status change handler function.
 *
 * @param       connHandle - connection handle
 * @param       changeType - type of change
 *
 * @return      none
 */
static void AudioProfile_HandleConnStatusCB( uint16 connHandle, uint8 changeType )
{ 
    // Make sure this is not loopback connection
    if ( connHandle != LOOPBACK_CONNHANDLE )
    {
      // Reset Client Char Config if connection has dropped
      if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED )      ||
           ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && 
             ( !linkDB_Up( connHandle ) ) ) )
      { 
        GATTServApp_InitCharCfg( connHandle, AudioProfileChar1Config );
        GATTServApp_InitCharCfg( connHandle, AudioProfileChar2Config );
      }
    }
}

bStatus_t AudioProfile_Notify( uint8 param, uint8 len, void *value )
{
    bStatus_t ret = SUCCESS;
    switch ( param )
    {  
	 case AUDIOPROFILE_CHAR2:
          VOID osal_memcpy( AudioProfileChar2, value, len );

            GATTServApp_ProcessCharCfg( AudioProfileChar2Config, AudioProfileChar2, FALSE,
                                    AudioProfileAttrTbl, GATT_NUM_ATTRS( AudioProfileAttrTbl ),
                                    INVALID_TASK_ID );      
        break;
          
      default:
        ret = INVALIDPARAMETER;
        break;
    }
    
    return ( ret );
}

bStatus_t AudioProfile_Write( uint16 connHandle, gattAttribute_t *pAttr,
                                 uint8 *pValue, uint8 len, uint16 offset )
{
      bStatus_t status = SUCCESS;
      // 16-bit UUID
      uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
      
      switch(uuid){
        case AUDIOPROFILE_CHAR1_UUID:

            if ( offset != 0 )
            {
                status = ATT_ERR_ATTR_NOT_LONG;
            }
          
            if ( status == SUCCESS ){
                uint8 *pCurValue = (uint8 *)pAttr->pValue;
                VOID osal_memcpy( pCurValue, pValue, len );
                //rxdata_process(pCurValue,len);
           
             }
          break;
          
          case GATT_CLIENT_CHAR_CFG_UUID:
            status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
                                                   offset, GATT_CLIENT_CFG_NOTIFY );
          break;
          default:
            status = ATT_ERR_ATTR_NOT_FOUND;
          break;
      }

  return status;
}

bStatus_t AudioProfile_Read( uint16 connHandle, gattAttribute_t *pAttr, 
                            uint8 *pValue, uint16 *pLen, uint16 offset, uint8 maxLen )
{
  bStatus_t status = SUCCESS;
  if(pAttr->type.len == ATT_BT_UUID_SIZE)
  {
   // 16-bit UUID
      uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
    LOG("16 uuid:%X\n\r",uuid);
      switch ( uuid )
      {
        case AUDIOPROFILE_CHAR1_UUID:
          *pLen = char1Tx_length;
          VOID osal_memcpy( pValue, pAttr->pValue, *pLen );
          break;
        case AUDIOPROFILE_CHAR2_UUID:
          *pLen=char2Tx_length;
          VOID osal_memcpy( pValue, pAttr->pValue, *pLen );
          break;
          
        default:
          // Should never get here! (characteristics 3 and 4 do not have read permissions)
          *pLen = 0;
          status = ATT_ERR_ATTR_NOT_FOUND;
		  LOG("uuid not find\n\r");
          break;
        
        
        }

  }
  else
  {
    uint16 uuid = BUILD_UINT16( pAttr->type.uuid[12], pAttr->type.uuid[13]);
	//LOG("128 uuid:%X\n\r",uuid);
      switch ( uuid )
      {
        case AUDIOPROFILE_CHAR1_UUID:
          *pLen = char1Tx_length;
          VOID osal_memcpy( pValue, pAttr->pValue, *pLen );
          break;
        case AUDIOPROFILE_CHAR2_UUID:
          *pLen=char2Tx_length;
          VOID osal_memcpy( pValue, pAttr->pValue, *pLen );
          break;
          
        default:
          // Should never get here! (characteristics 3 and 4 do not have read permissions)
          *pLen = 0;
          status = ATT_ERR_ATTR_NOT_FOUND;
		  LOG("uuid not find\n\r");
          break;
        
        
        }
  }
  
      
        return status;
}


/*********************************************************************
*********************************************************************/
